/*
Copyright (C) 2011  Christoph Schnack, Berlin (Germany)

This file is part of Tribuit.

    Tribuit is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Tribuit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Tribuit.  If not, see <http://www.gnu.org/licenses/>.
*/
package WordTable;

import java.awt.*;
import java.awt.print.*;
import java.util.HashMap;
import java.util.Vector;
import Storage.*;
import WordTable.WCSettings;

/**
 * @author Christoph Schnack
 *
 */
class Print implements Printable{
	Vector<Vector<Word>> pages = new Vector<Vector<Word>>();
	Vector<Word> words;
	HashMap<String,TermClass> tcsA,tcsB;
	boolean start = true;
	int termHeight=0;
	int tcHeight=0;
	int metaHeight=0;
	int termAscent=0;
	int termDescent=0;
	int tcAscent=0;
	int tcDescent=0;
	int latestX;
	boolean showPhonetics,showNote,showMetas,showSynonyms,showESentence,showTermClass,verticalSeparator;
	Font termFontBold,termFont,termFontItalic,metaKFont,metaVFont,tcFont;
	Vocabulary printvocabulary;
	Storage MAINVOC;
	WCSettings wcSettings;
	PrintSettings printSettings;
	
	public Print(Storage voc,Vector<Word> wordsArg, WCSettings wcOptsArg, PrintSettings PSArg, int termFontSize,int metaFontSize){
		termFont = new Font(Font.SERIF,Font.PLAIN,termFontSize);
		if(PSArg.getWordsBold())termFontBold = new Font(Font.SERIF,Font.BOLD,termFontSize);
		else termFontBold = termFont;
		termFontItalic = new Font(Font.SERIF,Font.ITALIC,termFontSize);
		metaKFont = new Font(Font.SERIF,Font.PLAIN,metaFontSize);
		metaVFont = new Font(Font.SERIF,Font.PLAIN,metaFontSize);
		tcFont = new Font(Font.SERIF,Font.ITALIC,metaFontSize);
		MAINVOC= voc;
		words = wordsArg;
		wcSettings= wcOptsArg;
		tcsA = MAINVOC.getVocabulary(wcSettings.getVocName()).getTermclassesA();
		tcsB = MAINVOC.getVocabulary(wcSettings.getVocName()).getTermclassesB();
		showPhonetics=wcSettings.getShowPhonetics();
		showNote=wcSettings.getShowNote();
		showMetas=wcSettings.getTestMetas();
		showSynonyms=wcSettings.getShowSynonyms();
		showESentence=wcSettings.getShowESentence();
		verticalSeparator = PSArg.getVerticalSeparator();
		showTermClass = PSArg.getShowTermClass();
	}
	
	
	public void fill(PageFormat pageFormat,Graphics g1){
		Graphics2D g = (Graphics2D) g1;
		int pageHeight = (int)pageFormat.getImageableHeight();
		//Word[] words = wtTestvocabulary.toArray(new Word[]{});
		FontMetrics metrics = g.getFontMetrics(termFontBold);
        termHeight = metrics.getAscent() + metrics.getDescent();
        termDescent = metrics.getDescent();
        termAscent = metrics.getAscent();
        termHeight = termAscent + termDescent;
        metrics = g.getFontMetrics(metaKFont);
        metaHeight = metrics.getAscent() + metrics.getDescent();
        metrics = g.getFontMetrics(tcFont);
        tcHeight = metrics.getAscent() + metrics.getDescent();
        tcAscent = metrics.getAscent();
        //if(SET.isVerbose())System.out.println("TERM: "+ termHeight+ "   tcHeight: "+ tcHeight + "     meta: "+ metaHeight);
       
        
        
        
        
        int heightOfPageEntries=termHeight*2;
        int minHeight = termHeight+tcHeight;
        int entryLangAHeight=0,entryLangBHeight=0;
        pages.add(new Vector<Word>());
        int x1=10;
		int x2 = (int)Math.round(pageFormat.getImageableWidth()/2)+x1;
		int metaInset=20;
		int reminderY=0,latestYpos=0,yposA,yposB;
		int sideAEnd = x2-(x1+(int)termFont.getStringBounds("-", g.getFontRenderContext()).getWidth()),sideBEnd=(int)Math.round(pageFormat.getImageableWidth());
		
		int meaningCounter=1;
		int spaceBetweenWords = (int)Math.round( ((double)termHeight)/2.0 ) ;
		for(Word w : words){
			reminderY=latestYpos+termHeight+spaceBetweenWords;
			yposA = reminderY;
			meaningCounter = 1;
			for(Meaning meaning : w.getMeaningVectorA()){
				yposA+=writeString(g,termFontBold, ((w.getMeaningVectorA().size()>1)?(meaningCounter++)+".: ":"")+meaning.getMeaningWithArticle(),x1,yposA,sideAEnd);
				if(showPhonetics&&meaning.hasPhonetic()){
					yposA-=termHeight;
					yposA+=writeString(g,termFont,(" ["+meaning.getPhonetic()+"]"),latestX,x1,yposA,sideAEnd);
				}
				if(meaning.hasCategory()){
					yposA-=termHeight;
					yposA+=writeString(g,termFontItalic," " + meaning.getCategory(),latestX,x1,yposA,sideAEnd);
				}
				if(showSynonyms && meaning.hasSynonyms()){
					yposA+=writeString(g,metaVFont,meaning.getSynonymsAsString(),x1,yposA,sideAEnd);
				}
				if(showMetas && meaning.hasMeta()){
					int keyWidth=0;
					for(String key : tcsA.get(w.getTermclassA()).getSortedKeys()){
						if(meaning.hasMetaEntryFor(key)){
							int tmpKeyWidth = (int)metaKFont.getStringBounds(key+":", g.getFontRenderContext()).getWidth();
							if(tmpKeyWidth>keyWidth)keyWidth=tmpKeyWidth+5;
						}
					}
					for(String key : tcsA.get(w.getTermclassA()).getSortedKeys()){
						if(meaning.hasMetaEntryFor(key)){
							writeString(g,metaKFont,key+":", x1+metaInset, yposA,sideAEnd);
							yposA+=writeString(g,metaVFont,w.getMetaA(key), x1+metaInset+keyWidth, yposA,sideAEnd);
						}
					}
				}
				if(showNote && meaning.hasNote()){
					yposA+=writeString(g,metaVFont,meaning.getNote(), x1, yposA,sideAEnd);
				}
				if(showESentence && meaning.hasExampleSentence()){
					yposA+=writeString(g,metaVFont,meaning.getExampleSentence(), x1, yposA,sideAEnd);
				}
			}
			if(showTermClass)yposA+=writeString(g,tcFont,w.getTermclassA(), x1, yposA,sideAEnd);
			
			yposB = reminderY;
			writeString(g,termFont,"-",x2-((int)Math.round( ((double)x1)/2 )+(int)termFont.getStringBounds("-", g.getFontRenderContext()).getWidth()),yposB,sideBEnd);
			meaningCounter = 1;
			for(Meaning meaning : w.getMeaningVectorB()){
				yposB+=writeString(g,termFontBold, ((w.getMeaningVectorB().size()>1)?(meaningCounter++)+".: ":"")+meaning.getMeaningWithArticle(),x2,yposB,sideBEnd);
				if(showPhonetics&&meaning.hasPhonetic()){
					yposB-=termHeight;
					yposB+=writeString(g,termFont,(" ["+meaning.getPhonetic()+"]"),latestX,x1,yposB,sideBEnd);
				}
				if(meaning.hasCategory()){
					yposB-=termHeight;
					yposB+=writeString(g,termFontItalic," " + meaning.getCategory(),latestX,x1,yposB,sideBEnd);
				}
				if(showSynonyms && meaning.hasSynonyms()){
					yposB+=writeString(g,metaVFont,meaning.getSynonymsAsString(),x2,yposB,sideBEnd);
				}
				if(showMetas && meaning.hasMeta()){
					int keyWidth=0;
					for(String key : tcsB.get(w.getTermclassB()).getSortedKeys()){
						if(meaning.hasMetaEntryFor(key)){
							int tmpKeyWidth = (int)metaKFont.getStringBounds(key+":", g.getFontRenderContext()).getWidth();
							if(tmpKeyWidth>keyWidth)keyWidth=tmpKeyWidth+5;
						}
					}
					for(String key : tcsB.get(w.getTermclassB()).getSortedKeys()){
						if(meaning.hasMetaEntryFor(key)){
							writeString(g,metaKFont,key+":", x2+metaInset, yposB,sideBEnd);
							yposB+=writeString(g,metaVFont,w.getMetaB(key), x2+metaInset+keyWidth, yposB,sideBEnd);
						}
					}
				}
				if(showNote && meaning.hasNote()){
					yposB+=writeString(g,metaVFont,meaning.getNote(), x2, yposB,sideBEnd);
				}
				if(showESentence && meaning.hasExampleSentence()){
					yposB+=writeString(g,metaVFont,meaning.getExampleSentence(), x2, yposB,sideBEnd);
				}
			}
			if(showTermClass)yposB+=writeString(g,tcFont,w.getTermclassB(), x2, yposB,sideBEnd);
			latestYpos=yposA>yposB?yposA:yposB;
		
		
		/*
		for(Word w : words){
			entryLangAHeight=0;
			entryLangBHeight=0;
			for(Meaning meaning : w.getMeaningVectorA()){
				entryLangAHeight+=writeString(g,termFont,meaning.getMeaningAsStringFull()+((showSynonyms && meaning.hasSynonyms())?", "+meaning.getSynonymsAsString():""),x1,heightOfPageEntries+entryLangAHeight,sideAEnd);
				entryLangAHeight+=writeString(g,tcFont,w.getTermclassA(), x1, heightOfPageEntries+entryLangAHeight,sideAEnd);
				if(showSynonyms && meaning.hasSynonyms()){
					entryLangAHeight+=termHeight;
				}
				if(showMetas && meaning.hasMeta()){
					for(String key : tcsA.get(w.getTermclassA()).getSortedKeys()){
						if(meaning.hasMetaEntryFor(key)) entryLangAHeight+=metaHeight;
					}
				}
				if(showNote && meaning.hasNote()){
					entryLangAHeight+=termHeight;
				}
				if(showESentence && meaning.hasExampleSentence()){
					entryLangAHeight+=termHeight;
				}
			}
			for(Meaning meaning : w.getMeaningVectorB()){
				entryLangBHeight+=minHeight;
				if(showSynonyms && meaning.hasSynonyms()){
					entryLangBHeight+=termHeight;
				}
				if(showMetas && meaning.hasMeta()){
					for(String key : tcsB.get(w.getTermclassB()).getSortedKeys()){
						if(meaning.hasMetaEntryFor(key)) entryLangBHeight+=metaHeight;
					}
				}
				if(showNote && meaning.hasNote()){
					entryLangBHeight+=termHeight;
				}
				if(showESentence && meaning.hasExampleSentence()){
					entryLangBHeight+=termHeight;
				}
			}*/
			//heightOfPageEntries+=(entryLangAHeight>entryLangBHeight)?entryLangAHeight:entryLangBHeight;
			if(latestYpos>=pageHeight-termHeight){
				pages.add(new Vector<Word>());
				latestYpos=termHeight*2;
			}
			pages.lastElement().add(w);
		}
	}

	@Override
	public int print(Graphics g1, PageFormat pageFormat, int arg2){
		if(start){
			start=false;
			fill(pageFormat,g1);
		}
		if(arg2==pages.size()){
			return NO_SUCH_PAGE;
		}
		Graphics2D g = (Graphics2D) g1;
		g.translate(pageFormat.getImageableX(),pageFormat.getImageableY());
		g.setColor(Color.black);
		Vector<Word> page = pages.elementAt(arg2);
		int meaningCounter=1;
		int x1=10;
		int x2 = (int)Math.round(pageFormat.getImageableWidth()/2)+x1;
		int metaInset=20;
		int reminderY=0,latestYpos=0,yposA,yposB;
		int spaceBetweenWords = (int)Math.round( ((double)termHeight)/2.0 ) ;
		int sideAEnd = x2-(x1+(int)termFont.getStringBounds("-", g.getFontRenderContext()).getWidth()),sideBEnd=(int)Math.round(pageFormat.getImageableWidth());
		if(verticalSeparator){
			g.setStroke(new BasicStroke(2));
			g.drawLine(sideAEnd, 10, sideAEnd, (int)pageFormat.getImageableHeight());
		}
		for(int i=0;i<page.size();i++){
			Word w = page.elementAt(i);
			reminderY=latestYpos+termHeight+spaceBetweenWords;
			yposA = reminderY;
			meaningCounter = 1;
			for(Meaning meaning : w.getMeaningVectorA()){
				yposA+=writeString(g,termFontBold, ((w.getMeaningVectorA().size()>1)?(meaningCounter++)+".: ":"")+meaning.getMeaningWithArticle(),x1,yposA,sideAEnd);
				if(showPhonetics&&meaning.hasPhonetic()){
					yposA-=termHeight;
					yposA+=writeString(g,termFont,(" ["+meaning.getPhonetic()+"]"),latestX,x1,yposA,sideAEnd);
				}
				if(meaning.hasCategory()){
					yposA-=termHeight;
					yposA+=writeString(g,termFontItalic," " + meaning.getCategory(),latestX,x1,yposA,sideAEnd);
				}
				if(showSynonyms && meaning.hasSynonyms()){
					yposA+=writeString(g,metaVFont,meaning.getSynonymsAsString(),x1,yposA,sideAEnd);
				}
				if(showMetas && meaning.hasMeta()){
					int keyWidth=0;
					for(String key : tcsA.get(w.getTermclassA()).getSortedKeys()){
						if(meaning.hasMetaEntryFor(key)){
							int tmpKeyWidth = (int)metaKFont.getStringBounds(key+":", g.getFontRenderContext()).getWidth();
							if(tmpKeyWidth>keyWidth)keyWidth=tmpKeyWidth+5;
						}
					}
					for(String key : tcsA.get(w.getTermclassA()).getSortedKeys()){
						if(meaning.hasMetaEntryFor(key)){
							writeString(g,metaKFont,key+":", x1+metaInset, yposA,sideAEnd);
							yposA+=writeString(g,metaVFont,w.getMetaA(key), x1+metaInset+keyWidth, yposA,sideAEnd);
						}
					}
				}
				if(showNote && meaning.hasNote()){
					yposA+=writeString(g,metaVFont,meaning.getNote(), x1, yposA,sideAEnd);
				}
				if(showESentence && meaning.hasExampleSentence()){
					yposA+=writeString(g,metaVFont,meaning.getExampleSentence(), x1, yposA,sideAEnd);
				}
			}
			if(showTermClass)yposA+=writeString(g,tcFont,w.getTermclassA(), x1, yposA,sideAEnd);
			
			yposB = reminderY;
			if(!verticalSeparator)writeString(g,termFont,"-",x2-((int)Math.round( ((double)x1)/2 )+(int)termFont.getStringBounds("-", g.getFontRenderContext()).getWidth()),yposB,sideBEnd);
			meaningCounter = 1;
			for(Meaning meaning : w.getMeaningVectorB()){
				yposB+=writeString(g,termFontBold, ((w.getMeaningVectorB().size()>1)?(meaningCounter++)+".: ":"")+meaning.getMeaningWithArticle(),x2,yposB,sideBEnd);
				if(showPhonetics&&meaning.hasPhonetic()){
					yposB-=termHeight;
					yposB += writeString(g,termFont,(" ["+meaning.getPhonetic()+"]"),latestX,x2,yposB,sideBEnd);
				}
				if(meaning.hasCategory()){
					yposB-=termHeight;
					yposB+=writeString(g,termFontItalic," " + meaning.getCategory(),latestX,x2,yposB,sideBEnd);
				}
				if(showSynonyms && meaning.hasSynonyms()){
					yposB+=writeString(g,metaVFont,meaning.getSynonymsAsString(),x2,yposB,sideBEnd);
				}
				if(showMetas && meaning.hasMeta()){
					int keyWidth=0;
					for(String key : tcsB.get(w.getTermclassB()).getSortedKeys()){
						if(meaning.hasMetaEntryFor(key)){
							int tmpKeyWidth = (int)metaKFont.getStringBounds(key+":", g.getFontRenderContext()).getWidth();
							if(tmpKeyWidth>keyWidth)keyWidth=tmpKeyWidth+5;
						}
					}
					for(String key : tcsB.get(w.getTermclassB()).getSortedKeys()){
						if(meaning.hasMetaEntryFor(key)){
							writeString(g,metaKFont,key+":", x2+metaInset, yposB,sideBEnd);
							yposB+=writeString(g,metaVFont,w.getMetaB(key), x2+metaInset+keyWidth, yposB,sideBEnd);
						}
					}
				}
				if(showNote && meaning.hasNote()){
					yposB+=writeString(g,metaVFont,meaning.getNote(), x2, yposB,sideBEnd);
				}
				if(showESentence && meaning.hasExampleSentence()){
					yposB+=writeString(g,metaVFont,meaning.getExampleSentence(), x2, yposB,sideBEnd);
				}
			}
			if(showTermClass)yposB+=writeString(g,tcFont,w.getTermclassB(), x2, yposB,sideBEnd);
			latestYpos=yposA>yposB?yposA:yposB;
		}
		return PAGE_EXISTS;
	}
	
	/**
	 * 
	 * 
	 * @author Christoph Schnack
	 * @param g Graphics2D object
	 * @param font Font object
	 * @param string text to write
	 * @param x x coordinate
	 * @param y y coordinate
	 * @param maxX horizontal border
	 */
	private int writeString(Graphics2D g, Font font, String string,int x, int y, int maxX){
		int stringWidth = (int)font.getStringBounds(string, g.getFontRenderContext()).getWidth();
		FontMetrics metrics = g.getFontMetrics(font);
        int fontHeight = metrics.getAscent() + metrics.getDescent();
        g.setFont(font);
		if(stringWidth>maxX-x){
			int counter=0;
			String shortenedString = string; 
			while((int)font.getStringBounds(shortenedString, g.getFontRenderContext()).getWidth()>maxX-x){
				shortenedString = string.substring(0,string.length()-counter++);
			}
			g.drawString(shortenedString, x, y);
			return fontHeight + writeString(g,font,string.substring(shortenedString.length()),x,y+fontHeight,maxX);
		}
		else{
			g.drawString(string, x,y);
			latestX = x + (int)font.getStringBounds(string, g.getFontRenderContext()).getWidth();
			return fontHeight;
		}
	}
	
	/**
	 * Writes a string starting at x and continues it at continueAtX in case of line break.
	 * @author Christoph Schnack
	 * @param g
	 * @param font
	 * @param string
	 * @param x
	 * @param continueAtX
	 * @param y
	 * @param maxX
	 * @return
	 */
	private int writeString(Graphics2D g, Font font, String string,int x, int continueAtX, int y, int maxX){
		int stringWidth = (int)font.getStringBounds(string, g.getFontRenderContext()).getWidth();
		FontMetrics metrics = g.getFontMetrics(font);
        int fontHeight = metrics.getAscent() + metrics.getDescent();
        g.setFont(font);
		if(stringWidth>maxX-x){
			int counter=0;
			String shortenedString = string; 
			while((int)font.getStringBounds(shortenedString, g.getFontRenderContext()).getWidth()>maxX-x){
				shortenedString = string.substring(0,string.length()-counter++);
			}
			g.drawString(shortenedString, x, y);
			return fontHeight + writeString(g,font,string.substring(shortenedString.length()),continueAtX,y+fontHeight,maxX);
		}
		else{
			g.drawString(string, x, y);
			latestX = x + (int)font.getStringBounds(string, g.getFontRenderContext()).getWidth();
			return fontHeight;
		}
	}
}